package com.xnyzc.lhy.order.service.impl.user.pay;

import com.alibaba.fastjson.JSON;
import com.alibaba.fastjson.JSONObject;
import com.baomidou.mybatisplus.core.toolkit.Wrappers;
import com.xnyzc.lhy.common.component.payment.AliPay;
import com.xnyzc.lhy.common.component.payment.WeChatPay;
import com.xnyzc.lhy.common.component.redis.RedisCommon;
import com.xnyzc.lhy.common.constant.RedisPrefixConstant;
import com.xnyzc.lhy.common.entity.Rv;
import com.xnyzc.lhy.common.exception.PangException;
import com.xnyzc.lhy.common.penum.EErrorCode;
import com.xnyzc.lhy.common.penum.carpool.EInvitationPayType;
import com.xnyzc.lhy.common.penum.carpool.EInvitationPeopleType;
import com.xnyzc.lhy.common.penum.carpool.EInvitationType;
import com.xnyzc.lhy.common.penum.order.EOrderNoType;
import com.xnyzc.lhy.common.penum.order.EOrderStatus;
import com.xnyzc.lhy.common.penum.pay.EPayDetailsButtonName;
import com.xnyzc.lhy.common.penum.pay.EPayListType;
import com.xnyzc.lhy.common.penum.pay.EPayMoneyLock;
import com.xnyzc.lhy.common.penum.pay.EPayType;
import com.xnyzc.lhy.common.penum.pay.ETransactionOrderNoType;
import com.xnyzc.lhy.common.penum.push.EDriverPushContent;
import com.xnyzc.lhy.common.penum.push.EJPushBalanceChangeType;
import com.xnyzc.lhy.common.penum.push.EJPushConfigKey;
import com.xnyzc.lhy.common.penum.push.EPushCode;
import com.xnyzc.lhy.common.penum.wallet.EDRecordType;
import com.xnyzc.lhy.common.penum.wallet.EIsTransaction;
import com.xnyzc.lhy.common.penum.wallet.ERecordType;
import com.xnyzc.lhy.common.util.CheckUtil;
import com.xnyzc.lhy.common.util.IDUtil;
import com.xnyzc.lhy.common.util.TokenUtil;
import com.xnyzc.lhy.order.entity.common.order.OrderCommon;
import com.xnyzc.lhy.order.entity.driver.wallet.OaDWallet;
import com.xnyzc.lhy.order.entity.driver.wallet.OaDWalletRecord;
import com.xnyzc.lhy.order.entity.order.OaCOrder;
import com.xnyzc.lhy.order.entity.order.OaCOrderApprovalOfficial;
import com.xnyzc.lhy.order.entity.order.OaCOrderDeptOfficial;
import com.xnyzc.lhy.order.entity.order.OaCOrderPersonal;
import com.xnyzc.lhy.order.entity.order.OaCOrderPersonalOfficial;
import com.xnyzc.lhy.order.entity.order.OaCSelfStroke;
import com.xnyzc.lhy.order.entity.order.OaDOrder;
import com.xnyzc.lhy.order.entity.param.user.pay.UserPayParam;
import com.xnyzc.lhy.order.entity.user.OaDUser;
import com.xnyzc.lhy.order.entity.user.wallet.OaCWallet;
import com.xnyzc.lhy.order.entity.user.wallet.OaCWalletRecord;
import com.xnyzc.lhy.order.entity.util.OrderUtil;
import com.xnyzc.lhy.order.entity.work.OaDWorkStatistics;
import com.xnyzc.lhy.order.feign.push.FeignMessageSendService;
import com.xnyzc.lhy.order.mapper.driver.wallet.OaDWalletMapper;
import com.xnyzc.lhy.order.mapper.driver.wallet.OaDWalletRecordMapper;
import com.xnyzc.lhy.order.mapper.order.OaCOrderApprovalOfficialMapper;
import com.xnyzc.lhy.order.mapper.order.OaCOrderDeptOfficialMapper;
import com.xnyzc.lhy.order.mapper.order.OaCOrderPersonalMapper;
import com.xnyzc.lhy.order.mapper.order.OaCOrderPersonalOfficialMapper;
import com.xnyzc.lhy.order.mapper.order.OaCSelfStrokeMapper;
import com.xnyzc.lhy.order.mapper.order.OaDOrderMapper;
import com.xnyzc.lhy.order.mapper.user.OaDUserMapper;
import com.xnyzc.lhy.order.mapper.user.wallet.OaCWalletMapper;
import com.xnyzc.lhy.order.mapper.user.wallet.OaCWalletRecordMapper;
import com.xnyzc.lhy.order.mapper.work.OaDWorkStatisticsMapper;
import com.xnyzc.lhy.order.service.order.IOaCCostDetailsService;
import com.xnyzc.lhy.order.service.user.pay.IOaCUserPayService;
import com.xnyzc.lhy.order.util.service.JPushBalanceChangeUtilService;
import com.xnyzc.lhy.resource.entity.jpush.BizResult;
import com.xnyzc.lhy.resource.entity.jpush.PushInfoEntity;
import lombok.extern.slf4j.Slf4j;
import org.apache.commons.lang3.StringUtils;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Service;

import java.math.BigDecimal;
import java.util.*;

/**
 * @Description 用户支付
 * @Author zhuyubin
 * @Date 2019/8/7 11:19
 **/
@Slf4j
@Service
public class OaCUserPayServiceImpl implements IOaCUserPayService {

    @Autowired
    private OaCWalletMapper oaCWalletMapper;
    @Autowired
    private OaCWalletRecordMapper oaCWalletRecordMapper;
    @Autowired
    private OaCOrderPersonalMapper oaCOrderPersonalMapper;
    @Autowired
    private OaCOrderPersonalOfficialMapper oaCOrderPersonalOfficialMapper;
    @Autowired
    private OaCOrderDeptOfficialMapper oaCOrderDeptOfficialMapper;
    @Autowired
    private OaCOrderApprovalOfficialMapper oaCOrderApprovalOfficialMapper;
    @Autowired
    private RedisCommon redisCommon;
    @Autowired
    private OaDWalletMapper oaDWalletMapper;
    @Autowired
    private OaDWalletRecordMapper oaDWalletRecordMapper;
    @Autowired
    private OaDWorkStatisticsMapper oaDWorkStatisticsMapper;
    @Autowired
    private OaCSelfStrokeMapper oaCSelfStrokeMapper;
    @Autowired
    private OaDOrderMapper oaDOrderMapper;
    @Autowired
    private JPushBalanceChangeUtilService jPushBalanceChangeUtilService;
    @Autowired
    private FeignMessageSendService feignMessageSendService;
    @Autowired
    private OaDUserMapper oaDUserMapper;
    @Autowired
    private IOaCCostDetailsService iOaCCostDetailsService;
    @Autowired
    private OrderCommon orderCommon;


    /**
     * 获取订单数据
     *
     * @param userId  用户id
     * @param orderNo 订单号
     * @param tag     租户
     * @return
     */
    @Override
    public Map<String, Object> getUserPay(Long userId, String orderNo, String tag) {
        OaCWallet oaCWallet = oaCWalletMapper.selectOne(
                Wrappers.<OaCWallet>lambdaQuery()
                        .eq(OaCWallet::getUserId, userId)
                        .eq(OaCWallet::getTag, tag)
        );
        if (CheckUtil.objIsEmpty(oaCWallet)) {
            throw PangException.create(EErrorCode.unWallet);
        }
        Map<String, Object> result = new HashMap<>(16);
        // 自费叫车
        if (orderNo.contains(EOrderNoType.ZFJC.getType())) {
            OaCOrderPersonal oaCOrderPersonal = oaCOrderPersonalMapper.selectOne(
                    Wrappers.<OaCOrderPersonal>lambdaQuery()
                            .eq(OaCOrder::getUserId, userId)
                            .eq(OaCOrder::getOrderNo, orderNo)
                            .eq(OaCOrder::getTag, tag)
            );
            if (CheckUtil.objIsEmpty(oaCOrderPersonal)) {
                throw PangException.create(EErrorCode.unOrderNo);
            }
            return this.getZFJC(oaCOrderPersonal, oaCWallet, result, tag);
        }
        // 个人公务
        else if (orderNo.contains(EOrderNoType.GRGW.getType())) {
            OaCOrderPersonalOfficial oaCOrderPersonalOfficial = oaCOrderPersonalOfficialMapper.selectOne(
                    Wrappers.<OaCOrderPersonalOfficial>lambdaQuery()
                            .eq(OaCOrder::getUserId, userId)
                            .eq(OaCOrder::getOrderNo, orderNo)
                            .eq(OaCOrder::getTag, tag)
            );
            if (CheckUtil.objIsEmpty(oaCOrderPersonalOfficial)) {
                throw PangException.create(EErrorCode.unOrderNo);
            }
            return this.getGRGW(oaCOrderPersonalOfficial, oaCWallet, result, tag);
        }
        // 部门公务
        else if (orderNo.contains(EOrderNoType.BMGW.getType())) {
            OaCOrderDeptOfficial oaCOrderDeptOfficial = oaCOrderDeptOfficialMapper.selectOne(
                    Wrappers.<OaCOrderDeptOfficial>lambdaQuery()
                            .eq(OaCOrder::getUserId, userId)
                            .eq(OaCOrder::getOrderNo, orderNo)
                            .eq(OaCOrder::getTag, tag)
            );
            if (CheckUtil.objIsEmpty(oaCOrderDeptOfficial)) {
                throw PangException.create(EErrorCode.unOrderNo);
            }
            return this.getBMGW(oaCOrderDeptOfficial, oaCWallet, result);
        }
        // 审批公务
        else if (orderNo.contains(EOrderNoType.SPGW.getType())) {
            OaCOrderApprovalOfficial oaCOrderApprovalOfficial = oaCOrderApprovalOfficialMapper.selectOne(
                    Wrappers.<OaCOrderApprovalOfficial>lambdaQuery()
                            .eq(OaCOrderApprovalOfficial::getUserId, userId)
                            .eq(OaCOrderApprovalOfficial::getOrderNo, orderNo)
                            .eq(OaCOrderApprovalOfficial::getTag, tag)
            );
            if (CheckUtil.objIsEmpty(oaCOrderApprovalOfficial)) {
                throw PangException.create(EErrorCode.unOrderNo);
            }
            return this.getSPGW(oaCOrderApprovalOfficial, oaCWallet, result, tag);
        }
        // 未知订单
        else {
            throw PangException.create(EErrorCode.unOrder);
        }
    }

    /**
     * 查看自费叫车封装
     *
     * @param oaCOrderPersonal 订单实体
     * @return
     */
    private Map<String, Object> getZFJC(OaCOrderPersonal oaCOrderPersonal, OaCWallet oaCWallet, Map<String, Object> result, String tag) {
        // 钱吧余额
        BigDecimal walletBalance = oaCWallet.getWalletBalance();
        BigDecimal zero = new BigDecimal(0);
        List<Map<String, Object>> list = new ArrayList<>();
        Integer orderStatus = oaCOrderPersonal.getOrderStatus();
        this.isOrder(orderStatus);
        list = this.addResule(EPayListType.orderNo.getName(), oaCOrderPersonal.getOrderNo(), list);
        // 总金额
        BigDecimal totalFee = oaCOrderPersonal.getTotalFee();
        list = this.addResule(EPayListType.myMoney.getName(), String.format("￥%s", totalFee), list);
        // 代付
        // 是否被邀约人查看
        boolean isBeInvitePeople = false;
        if (EInvitationType.personal.getValue().equals(oaCOrderPersonal.getInvitationType()) &&
                EInvitationPayType.invitePeoplePay.getValue().equals(oaCOrderPersonal.getInvitationPayType())){
            // 邀约拼车流水号
            String carpoolSerialNo = oaCOrderPersonal.getCarpoolSerialNo();
            // 被邀约人订单
            OaCOrderPersonal personal = this.iOaCCostDetailsService.getInvitationOaCOrderPersonal(tag, carpoolSerialNo);
            if (CheckUtil.objIsNotEmpty(personal) && EInvitationPeopleType.beInvitePeople.getValue().equals(oaCOrderPersonal.getInvitationPeopleType())){
                BigDecimal payTransactionFee = iOaCCostDetailsService.bigDecimalIsNull(personal.getTotalFee());
                list = this.addResule(EPayListType.payTransactionFee.getName(), String.format("-￥%s", payTransactionFee), list);
                isBeInvitePeople = true;
            }
        }
        // 支付后金额
        BigDecimal lastBalance = walletBalance.subtract(totalFee);
        if (lastBalance.compareTo(new BigDecimal(0)) == -1) {
            result.put("list", list);
            result.put("totalFee", totalFee.toString());
            result.put("balancePay", walletBalance.toString());
            result.put("otherPay", zero.subtract(lastBalance).toString());
        } else {
            result.put("list", list);
            result.put("totalFee", totalFee.toString());
            result.put("balancePay", totalFee.toString());
            result.put("otherPay", zero.toString());
        }
        result.put("isAmount", true);
        result.put("buttonName", EPayDetailsButtonName.confirmPay.getDesc());
        // 被邀约人查看
        if (isBeInvitePeople){
            result.put("balancePay", zero.toString());
            result.put("otherPay", zero.toString());
            result.put("totalFee", zero.toString());
            result.put("buttonName", EPayDetailsButtonName.confirmStroke.getDesc());
        }
        return result;
    }

    /**
     * 个人公务
     *
     * @param oaCOrderPersonalOfficial 个人公务订单实体
     * @return
     */
    private Map<String, Object> getGRGW(OaCOrderPersonalOfficial oaCOrderPersonalOfficial, OaCWallet oaCWallet, Map<String, Object> result, String tag) {
        // 钱包余额
        BigDecimal walletBalance = oaCWallet.getWalletBalance();
        // 个人额度
        BigDecimal personalOfficialBalance = oaCWallet.getPersonalOfficialBalance();
        BigDecimal zero = new BigDecimal(0);
        List<Map<String, Object>> list = new ArrayList<>();
        Integer orderStatus = oaCOrderPersonalOfficial.getOrderStatus();
        this.isOrder(orderStatus);
        list = this.addResule(EPayListType.orderNo.getName(), oaCOrderPersonalOfficial.getOrderNo(), list);
        // 私用
        String orderNo = oaCOrderPersonalOfficial.getOrderNo();
        BigDecimal priFee = this.getSelfFee(orderNo, tag);
        // 总金额
        BigDecimal totalFee = oaCOrderPersonalOfficial.getTotalFee();
        // 公用
        BigDecimal pubFee = totalFee.subtract(priFee);
        // 消费剩余个人额度
        BigDecimal lastAmount = personalOfficialBalance.subtract(pubFee);
        if (lastAmount.compareTo(zero) == -1) {
            result.put("buttonName", EPayDetailsButtonName.applyRaise.getDesc());
        }
        list = this.addResule(EPayListType.pubMoney.getName(), String.format("￥%s", pubFee), list);
        list = this.addResule(EPayListType.myMoney.getName(), String.format("￥%s", priFee), list);
        list = this.addResule(String.format(EPayListType.yesPersonalAmount.getName(), pubFee), String.format("-￥%s", pubFee), list);
        // 代付
        if (EInvitationType.personal.getValue().equals(oaCOrderPersonalOfficial.getInvitationType()) &&
                EInvitationPayType.invitePeoplePay.getValue().equals(oaCOrderPersonalOfficial.getInvitationPayType())){
            // 邀约拼车流水号
            String carpoolSerialNo = oaCOrderPersonalOfficial.getCarpoolSerialNo();
            // 被邀约人订单
            OaCOrderPersonal personal = iOaCCostDetailsService.getInvitationOaCOrderPersonal(tag, carpoolSerialNo);
            if (CheckUtil.objIsNotEmpty(personal) && EInvitationPeopleType.invitePeople.getValue().equals(oaCOrderPersonalOfficial.getInvitationPeopleType())){
                BigDecimal payTransactionFee = iOaCCostDetailsService.bigDecimalIsNull(personal.getTotalFee());
                list = this.addResule(EPayListType.payTransactionFee.getName(), String.format("￥%s", payTransactionFee), list);
                priFee = priFee.add(payTransactionFee);
            }
        }
        // 如果为空赋值为0
        if (priFee.compareTo(zero) == 0) {
            result.put("buttonName", EPayDetailsButtonName.confirmStroke.getDesc());
        } else {
            result.put("buttonName", EPayDetailsButtonName.confirmPay.getDesc());
        }
        BigDecimal lastBalance = walletBalance.subtract(priFee);
        if (lastBalance.compareTo(new BigDecimal(0)) == -1) {
            result.put("balancePay", walletBalance.toString());
            result.put("otherPay", zero.subtract(lastBalance).toString());
        } else {
            result.put("balancePay", priFee.toString());
            result.put("otherPay", zero.toString());
        }
        result.put("totalFee", priFee.toString());
        result.put("list", list);
        result.put("isAmount", this.isAmount(lastAmount));
        return result;
    }

    /**
     * 部门额度
     *
     * @param oaCOrderDeptOfficial 部门额度实体
     * @return
     */
    private Map<String, Object> getBMGW(OaCOrderDeptOfficial oaCOrderDeptOfficial, OaCWallet oaCWallet, Map<String, Object> result) {
        // TODO 部门额度(暂时未开启)
        BigDecimal deptOfficialBalance = oaCWallet.getDeptOfficialBalance();
        BigDecimal zero = new BigDecimal(0);
        Integer orderStatus = oaCOrderDeptOfficial.getOrderStatus();
        List<Map<String, Object>> list = new ArrayList<>();
        this.isOrder(orderStatus);
        list = this.addResule(EPayListType.orderNo.getName(), oaCOrderDeptOfficial.getOrderNo(), list);
        // 总金额
        BigDecimal totalFee = oaCOrderDeptOfficial.getTotalFee();
        // 剩余公务额度
        BigDecimal lastAmount = deptOfficialBalance.subtract(totalFee);
        list = this.addResule(EPayListType.officeMoney.getName(), String.format("￥%s", totalFee), list);
        list = this.addResule(String.format(EPayListType.yesOfficeAmount.getName(), totalFee.toString()), zero.subtract(totalFee).toString(), list);
        result.put("list", list);
        result.put("totalFee", new BigDecimal(0).toString());
        result.put("balancePay", zero.toString());
        result.put("otherPay", zero.toString());
        result.put("isAmount", this.isAmount(lastAmount));
        result.put("buttonName", EPayDetailsButtonName.confirmStroke.getDesc());
        return result;
    }

    /**
     * 审批公务
     *
     * @param oaCOrderApprovalOfficial 审批公务订单实体
     * @param result                   出参
     * @return
     */
    private Map<String, Object> getSPGW(OaCOrderApprovalOfficial oaCOrderApprovalOfficial, OaCWallet oaCWallet, Map<String, Object> result, String tag) {
        // 钱包余额
        BigDecimal walletBalance = oaCWallet.getWalletBalance();
        BigDecimal zero = new BigDecimal(0);
        List<Map<String, Object>> list = new ArrayList<>();
        Integer orderStatus = oaCOrderApprovalOfficial.getOrderStatus();
        this.isOrder(orderStatus);
        // 私用
        String orderNo = oaCOrderApprovalOfficial.getOrderNo();
        BigDecimal priFee = this.getSelfFee(orderNo, tag);
        list = this.addResule(EPayListType.orderNo.getName(), oaCOrderApprovalOfficial.getOrderNo(), list);
        list = this.addResule(EPayListType.myMoney.getName(), String.format("￥%s", priFee), list);
        // 代付
        if (EInvitationType.personal.getValue().equals(oaCOrderApprovalOfficial.getInvitationType()) &&
                EInvitationPayType.invitePeoplePay.getValue().equals(oaCOrderApprovalOfficial.getInvitationPayType())){
            // 邀约拼车流水号
            String carpoolSerialNo = oaCOrderApprovalOfficial.getCarpoolSerialNo();
            // 被邀约人订单
            OaCOrderPersonal personal = iOaCCostDetailsService.getInvitationOaCOrderPersonal(tag, carpoolSerialNo);
            if (CheckUtil.objIsNotEmpty(personal) && EInvitationPeopleType.invitePeople.getValue().equals(oaCOrderApprovalOfficial.getInvitationPeopleType())){
                BigDecimal payTransactionFee = personal.getTotalFee();
                list = this.addResule(EPayListType.payTransactionFee.getName(), String.format("￥%s", payTransactionFee), list);
                priFee = priFee.add(payTransactionFee);
            }
        }
        if (priFee.compareTo(zero) == 0) {
            result.put("buttonName", EPayDetailsButtonName.confirmStroke.getDesc());
        } else {
            result.put("buttonName", EPayDetailsButtonName.confirmPay.getDesc());
        }
        // 支付后金额
        BigDecimal lastBalance = walletBalance.subtract(priFee);
        if (lastBalance.compareTo(new BigDecimal(0)) == -1) {
            result.put("balancePay", walletBalance.toString());
            result.put("otherPay", zero.subtract(lastBalance).toString());
        } else {
            result.put("otherPay", zero.toString());
            result.put("balancePay", priFee.toString());
        }
        result.put("totalFee", priFee.toString());
        result.put("list", list);
        result.put("isAmount", true);
        return result;
    }

    /**
     * 拼参数
     *
     * @return
     */
    private List<Map<String, Object>> addResule(String name, Object value, List<Map<String, Object>> result) {
        Map<String, Object> map = new HashMap<>(16);
        map.put("name", name);
        map.put("value", value);
        result.add(map);
        return result;
    }

    /*###################################################获取支付页面数据#################################################################################################*/

    /**
     * 支付
     *
     * @param userId     用户id
     * @param tag        租户
     * @param orderNo    订单哈
     * @param balancePay 余额交易金额
     * @param otherPay   三方支付金额
     * @param payType    支付类型（0支付宝、1微信、 2余额）
     * @return
     */
    @Override
    public Map<String, Object> userPay(Long userId, String tag, String orderNo, BigDecimal balancePay, BigDecimal otherPay, Integer payType) {
        Map<String, Object> result = this.initUserPay();
        // 用户钱包
        OaCWallet oaCWallet = oaCWalletMapper.selectOne(
                Wrappers.<OaCWallet>lambdaQuery()
                        .eq(OaCWallet::getUserId, userId)
                        .eq(OaCWallet::getTag, tag)
        );
        if (CheckUtil.objIsEmpty(oaCWallet)) {
            throw PangException.create(EErrorCode.unWallet);
        }
        // 自费叫车
        if (orderNo.contains(EOrderNoType.ZFJC.getType())) {
            OaCOrderPersonal oaCOrderPersonal = oaCOrderPersonalMapper.selectOne(
                    Wrappers.<OaCOrderPersonal>lambdaQuery()
                            .eq(OaCOrder::getUserId, userId)
                            .eq(OaCOrder::getTag, tag)
                            .eq(OaCOrder::getOrderNo, orderNo)
            );
            if (CheckUtil.objIsEmpty(oaCOrderPersonal)) {
                throw PangException.create(EErrorCode.unOrder);
            }
            return this.payZFJC(oaCOrderPersonal, oaCWallet, balancePay, otherPay, payType, orderNo, userId, tag, result);
        }
        // 个人公务
        else if (orderNo.contains(EOrderNoType.GRGW.getType())) {
            OaCOrderPersonalOfficial oaCOrderPersonalOfficial = oaCOrderPersonalOfficialMapper.selectOne(
                    Wrappers.<OaCOrderPersonalOfficial>lambdaQuery()
                            .eq(OaCOrder::getUserId, userId)
                            .eq(OaCOrder::getTag, tag)
                            .eq(OaCOrder::getOrderNo, orderNo)
            );
            if (CheckUtil.objIsEmpty(oaCOrderPersonalOfficial)) {
                throw PangException.create(EErrorCode.unOrder);
            }
            return this.payGRGW(oaCOrderPersonalOfficial, oaCWallet, balancePay, otherPay, payType, orderNo, userId, tag, result);
        }
        // TODO 部门公务(暂时未开放)
        else if (orderNo.contains(EOrderNoType.BMGW.getType())) {
            OaCOrderDeptOfficial oaCOrderDeptOfficial = oaCOrderDeptOfficialMapper.selectOne(
                    Wrappers.<OaCOrderDeptOfficial>lambdaQuery()
                            .eq(OaCOrder::getUserId, userId)
                            .eq(OaCOrder::getTag, tag)
                            .eq(OaCOrder::getOrderNo, orderNo)
            );
            if (CheckUtil.objIsEmpty(oaCOrderDeptOfficial)) {
                throw PangException.create(EErrorCode.unOrder);
            }
            return this.payBMGW(oaCOrderDeptOfficial, oaCWallet, orderNo, userId, tag, result);
        }
        // 审批公务
        else if (orderNo.contains(EOrderNoType.SPGW.getType())) {
            OaCOrderApprovalOfficial oaCOrderApprovalOfficial = oaCOrderApprovalOfficialMapper.selectOne(
                    Wrappers.<OaCOrderApprovalOfficial>lambdaQuery()
                            .eq(OaCOrderApprovalOfficial::getUserId, userId)
                            .eq(OaCOrderApprovalOfficial::getTag, tag)
                            .eq(OaCOrderApprovalOfficial::getOrderNo, orderNo)
            );
            if (CheckUtil.objIsEmpty(oaCOrderApprovalOfficial)) {
                throw PangException.create(EErrorCode.unOrder);
            }
            return this.paySPGW(oaCOrderApprovalOfficial, oaCWallet, balancePay, otherPay, payType, orderNo, userId, tag, result);
        }
        // 非法订单号
        else {
            throw PangException.create(EErrorCode.unOrderNo);
        }
    }

    /**
     * 自费叫车封装
     *
     * @param oaCOrderPersonal 自费叫车账单实体
     * @param oaCWallet        钱吧实体
     * @param balancePay       前端余额金额
     * @param otherPay         前端三方支付金额
     * @param userId           用户id
     * @param payType          三方交易类型
     * @param orderNo          订单号
     * @param result           出参
     * @param tag              租户
     * @return
     */
    private Map<String, Object> payZFJC(
            OaCOrderPersonal oaCOrderPersonal,
            OaCWallet oaCWallet,
            BigDecimal balancePay,
            BigDecimal otherPay,
            Integer payType,
            String orderNo,
            Long userId,
            String tag,
            Map<String, Object> result
    ) {
        // 声明0
        BigDecimal zero = new BigDecimal(0);
        // 钱包余额
        BigDecimal walletBalance = oaCWallet.getWalletBalance();
        BigDecimal personalOfficialBalance = oaCWallet.getPersonalOfficialBalance();
        BigDecimal deptOfficialBalance = oaCWallet.getDeptOfficialBalance();
        Date date = new Date();
        // 验证是否是待支付订单
        Integer orderStatus = oaCOrderPersonal.getOrderStatus();
        this.isOrder(orderStatus);
        // 总金额
        BigDecimal totalFee = oaCOrderPersonal.getTotalFee();
        // 司机应得收入
        BigDecimal drawFee = oaCOrderPersonal.getDrawFee();
        // 代付
        if (EInvitationType.personal.getValue().equals(oaCOrderPersonal.getInvitationType()) &&
                EInvitationPayType.invitePeoplePay.getValue().equals(oaCOrderPersonal.getInvitationPayType())){
            // 邀约拼车流水号
            String carpoolSerialNo = oaCOrderPersonal.getCarpoolSerialNo();
            // 被邀约人订单
            OaCOrderPersonal personal = iOaCCostDetailsService.getInvitationOaCOrderPersonal(tag, carpoolSerialNo);
            if (CheckUtil.objIsNotEmpty(personal) && EInvitationPeopleType.beInvitePeople.getValue().equals(oaCOrderPersonal.getInvitationPeopleType())){
                result.put("payType", EPayType.balance.getType());
                result.put("payResultStr", EErrorCode.confirmStrokeSuccess.getDesc());
                return result;
            }
        }
        // 消费剩余金额
        BigDecimal lastMoney = walletBalance.subtract(totalFee);
        // 余额不够三方来凑
        if (lastMoney.compareTo(zero) == -1) {
            //计算三方支付的金额
            BigDecimal otherMoney = zero.subtract(lastMoney);
            // 校验是否前后端支付金额一致
            if (!(walletBalance.compareTo(balancePay) == 0 && otherMoney.compareTo(otherPay) == 0)) {
                throw PangException.create(EErrorCode.payFailure);
            }
            // 给余额上锁
            this.lockOaCWallet(oaCWallet, EPayMoneyLock.no, EPayMoneyLock.yes, EPayMoneyLock.yes, userId, date);
            return this.otherPay(otherMoney, payType, orderNo, EOrderNoType.ZFJC, result);
        }
        // 余额够直接支付
        else {
            if (totalFee.compareTo(balancePay) != 0) {
                throw PangException.create(EErrorCode.payFailure);
            }
            // 更新钱包余额
            this.updateOaCWallet(oaCWallet, lastMoney, personalOfficialBalance, deptOfficialBalance, userId, date);
            // 插入钱包记录表
            this.insertOaCWalletRecord(userId, orderNo, totalFee, lastMoney, personalOfficialBalance, deptOfficialBalance, ERecordType.moneyDisbursement, OrderUtil.transactionOrderNo(ETransactionOrderNoType.balancePay), date, tag, EIsTransaction.paySuccess);
            // 更新司机钱包
            this.updateDriverWallet(oaCOrderPersonal.getDriverId(), userId, tag, drawFee, orderNo, EDRecordType.balanceIncome, OrderUtil.transactionOrderNo(ETransactionOrderNoType.balancePay));
            // 更新订单
            this.updateOaCOrderPersonal(oaCOrderPersonal, totalFee, date, userId, EPayType.balance);
            result.put("payType", EPayType.balance.getType());
            result.put("payResultStr", EErrorCode.paySuccess.getDesc());
            return result;
        }
    }

    /**
     * 个人公务封装
     *
     * @param oaCOrderPersonalOfficial 个人公务账单实体
     * @param oaCWallet                钱吧实体
     * @param balancePay               前端余额金额
     * @param otherPay                 前端三方支付金额
     * @param userId                   用户id
     * @param payType                  三方交易类型
     * @param orderNo                  订单号
     * @param result                   出参
     * @param tag                      租户
     * @return
     */
    private Map<String, Object> payGRGW(
            OaCOrderPersonalOfficial oaCOrderPersonalOfficial,
            OaCWallet oaCWallet,
            BigDecimal balancePay,
            BigDecimal otherPay,
            Integer payType,
            String orderNo,
            Long userId,
            String tag,
            Map<String, Object> result
    ) {
        // 余额
        BigDecimal walletBalance = oaCWallet.getWalletBalance();
        // 个人额度
        BigDecimal personalOfficialBalance = oaCWallet.getPersonalOfficialBalance();
        BigDecimal deptOfficialBalance = oaCWallet.getDeptOfficialBalance();
        Date date = new Date();
        Integer orderStatus = oaCOrderPersonalOfficial.getOrderStatus();
        this.isOrder(orderStatus);
        // 邀约拼车流水号
        String carpoolSerialNo = oaCOrderPersonalOfficial.getCarpoolSerialNo();
        // 声明0
        BigDecimal zero = new BigDecimal(0);
        // 总金额
        BigDecimal totalFee = oaCOrderPersonalOfficial.getTotalFee();
        // 私用
        BigDecimal priFee = this.getSelfFee(orderNo, tag);
        // 司机应得收入
        BigDecimal drawFee = oaCOrderPersonalOfficial.getDrawFee();
        // 公用
        BigDecimal pubFee = totalFee.subtract(priFee);
        // 代付
        OaCOrderPersonal personal = null;
        if (EInvitationType.personal.getValue().equals(oaCOrderPersonalOfficial.getInvitationType()) &&
                EInvitationPayType.invitePeoplePay.getValue().equals(oaCOrderPersonalOfficial.getInvitationPayType())){
            // 被邀约人订单
            personal = iOaCCostDetailsService.getInvitationOaCOrderPersonal(tag, carpoolSerialNo);
            if (CheckUtil.objIsNotEmpty(personal) && EInvitationPeopleType.invitePeople.getValue().equals(oaCOrderPersonalOfficial.getInvitationPeopleType())){
                BigDecimal payTransactionFee = iOaCCostDetailsService.bigDecimalIsNull(personal.getTotalFee());
                priFee = priFee.add(payTransactionFee);
            }
        }
        // 消费剩余额度
        BigDecimal lastAmount = personalOfficialBalance.subtract(pubFee);
        if (lastAmount.compareTo(zero) == -1) {
            throw PangException.create(EErrorCode.deficiencyLimit);
        }
        // 有私用路段
        if (priFee.compareTo(zero) == 1) {
            // 剩余余额
            BigDecimal lastMoney = walletBalance.subtract(priFee);
            if (lastMoney.compareTo(zero) == -1) {
                //计算三方支付的金额
                BigDecimal otherMoney = zero.subtract(lastMoney);
                // 校验是否前后端支付金额一致
                if (!(walletBalance.compareTo(balancePay) == 0 && otherMoney.compareTo(otherPay) == 0)) {
                    throw PangException.create(EErrorCode.payFailure);
                }
                // 给余额与个人额度上锁
                this.lockOaCWallet(oaCWallet, EPayMoneyLock.no, EPayMoneyLock.no, null, userId, date);
                return this.otherPay(otherMoney, payType, orderNo, EOrderNoType.GRGW, result);
            } else {
                // 验证前后端余额支付是否一致
                if (priFee.compareTo(balancePay) != 0) {
                    throw PangException.create(EErrorCode.payFailure);
                }
                // 更新钱包
                this.updateOaCWallet(oaCWallet, lastMoney, lastAmount, deptOfficialBalance, userId, date);
                // 插入钱包记录
                // 个人额度
                this.insertOaCWalletRecord(userId, orderNo, pubFee, walletBalance, lastAmount, deptOfficialBalance, ERecordType.myDisbursement, OrderUtil.transactionOrderNo(ETransactionOrderNoType.personalBusiness), date, tag, EIsTransaction.paySuccess);
                // 余额
                this.insertOaCWalletRecord(userId, orderNo, priFee, lastMoney, lastAmount, deptOfficialBalance, ERecordType.moneyDisbursement, OrderUtil.transactionOrderNo(ETransactionOrderNoType.balancePay), date, tag, EIsTransaction.paySuccess);
                // 更新司机钱包
                // 被邀人抽成费
                if (CheckUtil.objIsNotEmpty(personal) && CheckUtil.objIsNotEmpty(personal.getDrawFee())){
                    drawFee = drawFee.add(personal.getDrawFee());
                }
                this.updateDriverWallet(oaCOrderPersonalOfficial.getDriverId(), userId, tag, drawFee, orderNo, EDRecordType.balanceIncome, OrderUtil.transactionOrderNo(ETransactionOrderNoType.personalBusiness));
                // 修改订单
                // 更新被邀人订单
                if (CheckUtil.objIsNotEmpty(personal)){
                    this.updateOaCOrderPersonal(personal, personal.getTotalFee(), date, userId, EPayType.balance);
                }
                this.updateOaCOrderPersonalOfficial(oaCOrderPersonalOfficial, totalFee, date, userId, EPayType.balance);
                result.put("payResultStr", EErrorCode.paySuccess.getDesc());
                result.put("payType", EPayType.balance.getType());
                return result;
            }
        }
        // 没有私用路段
        else {
            // 个人额度支付
            // 更新钱包
            this.updateOaCWallet(oaCWallet, walletBalance, lastAmount, deptOfficialBalance, userId, date);
            // 插入钱包记录
            this.insertOaCWalletRecord(userId, orderNo, totalFee, walletBalance, lastAmount, deptOfficialBalance, ERecordType.myDisbursement, OrderUtil.transactionOrderNo(ETransactionOrderNoType.personalBusiness), date, tag, EIsTransaction.paySuccess);
            // 更新司机钱包
            this.updateDriverWallet(oaCOrderPersonalOfficial.getDriverId(), userId, tag, drawFee, orderNo, EDRecordType.balanceIncome, OrderUtil.transactionOrderNo(ETransactionOrderNoType.personalBusiness));
            // 更新订单
            this.updateOaCOrderPersonalOfficial(oaCOrderPersonalOfficial, totalFee, date, userId, EPayType.balance);
            result.put("payResultStr", EErrorCode.paySuccess.getDesc());
            result.put("payType", EPayType.balance.getType());
            return result;
        }
    }

    /**
     * 部门公务封装
     *
     * @param oaCOrderDeptOfficial 部门公务订单实体
     * @param oaCWallet            钱吧实体
     * @param userId               用户id
     * @param orderNo              订单号
     * @param result               出参
     * @param tag                  租户
     * @return
     */
    private Map<String, Object> payBMGW(
            OaCOrderDeptOfficial oaCOrderDeptOfficial,
            OaCWallet oaCWallet,
            String orderNo,
            Long userId,
            String tag,
            Map<String, Object> result
    ) {
        BigDecimal walletBalance = oaCWallet.getWalletBalance();
        BigDecimal personalOfficialBalance = oaCWallet.getPersonalOfficialBalance();
        // 部门额度
        BigDecimal deptOfficialBalance = oaCWallet.getDeptOfficialBalance();
        Date date = new Date();
        Integer orderStatus = oaCOrderDeptOfficial.getOrderStatus();
        this.isOrder(orderStatus);
        // 司机应得收入
        BigDecimal drawFee = oaCOrderDeptOfficial.getDrawFee();
        // 总金额
        BigDecimal totalFee = oaCOrderDeptOfficial.getTotalFee();
        // 剩余额度
        BigDecimal lastAmount = deptOfficialBalance.subtract(totalFee);
        // 声明 0
        BigDecimal zero = new BigDecimal(0);
        if (lastAmount.compareTo(zero) == -1) {
            throw PangException.create(EErrorCode.deficiencyLimit);
        }
        // 修改部门额度
        this.updateOaCWallet(oaCWallet, walletBalance, personalOfficialBalance, lastAmount, userId, date);
        // 插入记录
        this.insertOaCWalletRecord(userId, orderNo, totalFee, walletBalance, personalOfficialBalance, lastAmount, ERecordType.officialDisbursement, OrderUtil.transactionOrderNo(ETransactionOrderNoType.deptService), date, tag, EIsTransaction.paySuccess);
        // 更新司机钱包
        this.updateDriverWallet(oaCOrderDeptOfficial.getDriverId(), userId, tag, drawFee, orderNo, EDRecordType.balanceIncome, OrderUtil.transactionOrderNo(ETransactionOrderNoType.deptService));
        // 修改订单
        this.updateOaCOrderDectOfficial(oaCOrderDeptOfficial, totalFee, date, userId, EPayType.balance);
        result.put("payType", EPayType.balance.getType());
        result.put("payResultStr", EErrorCode.paySuccess.getDesc());
        return result;
    }

    /**
     * 审批公务封装
     *
     * @param oaCOrderApprovalOfficial 部门公务订单实体
     * @param oaCWallet                钱吧实体
     * @param userId                   用户id
     * @param orderNo                  订单号
     * @param result                   出参
     * @param tag                      租户
     * @return
     */
    private Map<String, Object> paySPGW(
            OaCOrderApprovalOfficial oaCOrderApprovalOfficial,
            OaCWallet oaCWallet,
            BigDecimal balancePay,
            BigDecimal otherPay,
            Integer payType,
            String orderNo,
            Long userId,
            String tag,
            Map<String, Object> result
    ) {
        BigDecimal walletBalance = oaCWallet.getWalletBalance();
        BigDecimal personalOfficialBalance = oaCWallet.getPersonalOfficialBalance();
        BigDecimal deptOfficialBalance = oaCWallet.getDeptOfficialBalance();
        Integer orderStatus = oaCOrderApprovalOfficial.getOrderStatus();
        this.isOrder(orderStatus);
        Date date = new Date();
        // 声明0
        BigDecimal zero = new BigDecimal(0);
        // 私用费用
        BigDecimal priFee = this.getSelfFee(orderNo, tag);
        // 司机应得收入
        BigDecimal drawFee = oaCOrderApprovalOfficial.getDrawFee();
        // 代付
        OaCOrderPersonal personal = null;
        if (EInvitationType.personal.getValue().equals(oaCOrderApprovalOfficial.getInvitationType()) &&
                EInvitationPayType.invitePeoplePay.getValue().equals(oaCOrderApprovalOfficial.getInvitationPayType())){
            // 邀约拼车流水号
            String carpoolSerialNo = oaCOrderApprovalOfficial.getCarpoolSerialNo();
            // 被邀约人订单
            personal = iOaCCostDetailsService.getInvitationOaCOrderPersonal(tag, carpoolSerialNo);
            if (CheckUtil.objIsNotEmpty(personal) && EInvitationPeopleType.invitePeople.getValue().equals(oaCOrderApprovalOfficial.getInvitationPeopleType())){
                BigDecimal payTransactionFee = iOaCCostDetailsService.bigDecimalIsNull(personal.getTotalFee());
                priFee = priFee.add(payTransactionFee);
            }
        }
        // 剩余余额
        BigDecimal lastBalance = walletBalance.subtract(priFee);
        // 余额不够
        if (lastBalance.compareTo(zero) == -1) {
            //计算三方支付的金额
            BigDecimal otherMoney = zero.subtract(lastBalance);
            // 校验是否前后端支付金额一致
            if (!(walletBalance.compareTo(balancePay) == 0 && otherMoney.compareTo(otherPay) == 0)) {
                throw PangException.create(EErrorCode.payFailure);
            }
            // 给余额与个人额度上锁
            this.lockOaCWallet(oaCWallet, EPayMoneyLock.no, null, null, userId, date);
            return this.otherPay(otherMoney, payType, orderNo, EOrderNoType.SPGW, result);
        } else {
            // 验证前后端余额支付是否一致
            if (priFee.compareTo(balancePay) != 0) {
                throw PangException.create(EErrorCode.payFailure);
            }
            // 更新钱包
            this.updateOaCWallet(oaCWallet, lastBalance, personalOfficialBalance, deptOfficialBalance, userId, date);
            // 插入余额记录
            this.insertOaCWalletRecord(userId, orderNo, priFee, lastBalance, personalOfficialBalance, deptOfficialBalance, ERecordType.moneyDisbursement, OrderUtil.transactionOrderNo(ETransactionOrderNoType.balancePay), date, tag, EIsTransaction.paySuccess);
            // 更新司机钱包
            // 被邀人抽成费
            if (CheckUtil.objIsNotEmpty(personal) && CheckUtil.objIsNotEmpty(personal.getDrawFee())){
                drawFee = drawFee.add(personal.getDrawFee());
            }
            this.updateDriverWallet(oaCOrderApprovalOfficial.getDriverId(), userId, tag, drawFee, orderNo, EDRecordType.balanceIncome, OrderUtil.transactionOrderNo(ETransactionOrderNoType.personalBusiness));
            // 订单额度费用
            // 更新被邀人订单
            if (CheckUtil.objIsNotEmpty(personal)){
                this.updateOaCOrderPersonal(personal, personal.getTotalFee(), date, userId, EPayType.balance);
            }
            BigDecimal totalFee = oaCOrderApprovalOfficial.getTotalFee();
            // 修改订单
            this.updateOaCOrderApprovalOfficial(oaCOrderApprovalOfficial, totalFee, date, userId, EPayType.balance);
            result.put("payType", EPayType.balance.getType());
            result.put("payResultStr", EErrorCode.paySuccess.getDesc());
            return result;
        }
    }

    /**
     * 调用三方支付并给余额上锁
     *
     * @param otherMoney 三方后端金额
     * @param payType    交易类型
     * @param orderNo    订单号
     * @param result     出参
     * @return
     */
    private Map<String, Object> otherPay(BigDecimal otherMoney, Integer payType, String orderNo, EOrderNoType eOrderNoType, Map<String, Object> result) {
        // 微信
        if (EPayType.weChat.getType().equals(payType)) {
            result.put("payType", EPayType.weChat.getType());
            result.put("payResultMap", WeChatPay.getWXPayParam(orderNo, eOrderNoType.getDesc(), otherMoney.toString(), new JSONObject()));
            result.put("payResultStr", "");
            return result;
        }
        // 支付宝
        else if (EPayType.alipay.getType().equals(payType)) {
            result.put("payType", EPayType.alipay.getType());
            result.put("payResultMap", new HashMap<>(16));
            result.put("payResultStr", AliPay.getAliPayParam(orderNo, eOrderNoType.getDesc(), otherMoney.toString(), new JSONObject()));
            return result;
        }
        // 非法类型
        else {
            throw PangException.create(EErrorCode.unPayType);
        }
    }

    /**
     * 余额上锁
     * @param oaCWallet 钱包实体
     * @param userId 用户id
     * @param date 当前时间
     */
    /**
     * 钱包余额与额度上锁 0不锁 1锁
     *
     * @param oaCWallet             钱包实体
     * @param balancelEPayMoneyLock 余额锁
     * @param personalEPayMoneyLock 个人额度锁
     * @param deptEPayMoneyLock     部门额度锁
     * @param userId                用户id
     * @param date                  当前时间
     */
    private void lockOaCWallet(OaCWallet oaCWallet, EPayMoneyLock balancelEPayMoneyLock, EPayMoneyLock personalEPayMoneyLock, EPayMoneyLock deptEPayMoneyLock, Long userId, Date date) {
        // 给余额上锁
        // 获取版本锁
        Long version = oaCWalletMapper.selectById(oaCWallet.getWalletId()).getVersion();
        OaCWallet updateOaCWallet = new OaCWallet();
        updateOaCWallet.setWalletId(oaCWallet.getWalletId());
        updateOaCWallet.setVersion(version);
        if (CheckUtil.objIsNotEmpty(balancelEPayMoneyLock)) {
            updateOaCWallet.setIsBalancelPay(balancelEPayMoneyLock.getType());
        }
        if (CheckUtil.objIsNotEmpty(personalEPayMoneyLock)) {
            updateOaCWallet.setIsPersonalPay(personalEPayMoneyLock.getType());
        }
        if (CheckUtil.objIsNotEmpty(deptEPayMoneyLock)) {
            updateOaCWallet.setIsDeptPay(deptEPayMoneyLock.getType());
        }
        updateOaCWallet.setUpdateUser(userId);
        updateOaCWallet.setUpdateTime(date);
        int i = oaCWalletMapper.updateById(updateOaCWallet);
        if (i != 1) {
            throw PangException.create(EErrorCode.payFailure);
        }
    }

    /**
     * 更新钱包余额
     *
     * @param oaCWallet               钱包实体
     * @param walletBalance           剩余余额
     * @param personalOfficialBalance 个人额度
     * @param deptOfficialBalance     部门余额
     * @param userId                  用户id
     * @param date                    当前时间
     */
    @Override
    public void updateOaCWallet(OaCWallet oaCWallet, BigDecimal walletBalance, BigDecimal personalOfficialBalance, BigDecimal deptOfficialBalance, Long userId, Date date) {
        // 更新钱包余额
        // 获取版本锁
        Long version = oaCWalletMapper.selectById(oaCWallet.getWalletId()).getVersion();
        OaCWallet updateOaCWallet = new OaCWallet();
        updateOaCWallet.setWalletId(oaCWallet.getWalletId());
        updateOaCWallet.setVersion(version);
        if (CheckUtil.objIsNotEmpty(walletBalance)) {
            updateOaCWallet.setWalletBalance(walletBalance);
        }
        if (CheckUtil.objIsNotEmpty(personalOfficialBalance)) {
            updateOaCWallet.setPersonalOfficialBalance(personalOfficialBalance);
        }
        if (CheckUtil.objIsNotEmpty(deptOfficialBalance)) {
            updateOaCWallet.setDeptOfficialBalance(deptOfficialBalance);
        }
        updateOaCWallet.setIsBalancelPay(EPayMoneyLock.yes.getType());
        updateOaCWallet.setIsPersonalPay(EPayMoneyLock.yes.getType());
        updateOaCWallet.setIsDeptPay(EPayMoneyLock.yes.getType());
        updateOaCWallet.setUpdateUser(userId);
        updateOaCWallet.setUpdateTime(date);
        int i = oaCWalletMapper.updateById(updateOaCWallet);
        if (i != 1) {
            throw PangException.create(EErrorCode.payFailure);
        }
    }

    /**
     * 插入支付记录
     *
     * @param userId                  用户id
     * @param orderNo                 订单号
     * @param totalFee                总金额
     * @param walletBalance           钱包余额
     * @param personalOfficialBalance 个人额度
     * @param deptOfficialBalance     部门额度
     * @param eRecordType             支付类型
     * @param transactionOrderNo      交易凭证号
     * @param date                    当前时间
     * @param tag                     租户
     * @param eIsTransaction          是否成功枚举
     */
    @Override
    public void insertOaCWalletRecord(
            Long userId,
            String orderNo,
            BigDecimal totalFee,
            BigDecimal walletBalance,
            BigDecimal personalOfficialBalance,
            BigDecimal deptOfficialBalance,
            ERecordType eRecordType,
            String transactionOrderNo,
            Date date,
            String tag,
            EIsTransaction eIsTransaction) {
        // 插入钱包记录表
        OaCWalletRecord oaCWalletRecord = new OaCWalletRecord();
        Long recordId = IDUtil.nextId();
        oaCWalletRecord.setRecordId(recordId);
        oaCWalletRecord.setUserId(userId);
        oaCWalletRecord.setOrderNo(orderNo);
        oaCWalletRecord.setActualAmount(totalFee);
        oaCWalletRecord.setWalletBalance(walletBalance);
        oaCWalletRecord.setPersonalOfficialBalance(personalOfficialBalance);
        oaCWalletRecord.setDeptOfficialBalance(deptOfficialBalance);
        oaCWalletRecord.setRecordType(eRecordType.getType());
        oaCWalletRecord.setIsTransaction(eIsTransaction.getValue());
        oaCWalletRecord.setTransactionTime(date);
        oaCWalletRecord.setTransactionOrderNo(transactionOrderNo);
        oaCWalletRecord.setTag(tag);
        oaCWalletRecord.setCreateUser(userId);
        oaCWalletRecord.setCreateTime(date);
        oaCWalletRecord.setUpdateUser(userId);
        oaCWalletRecord.setUpdateTime(date);
        oaCWalletRecordMapper.insert(oaCWalletRecord);

        // 极光推送余额变动
        if (ERecordType.moneyTopUp.getType().equals(eRecordType.getType())){
            jPushBalanceChangeUtilService.passengerPush(userId, tag, EJPushBalanceChangeType.recharge.getValue(), recordId, totalFee);
        }
        else {
            jPushBalanceChangeUtilService.passengerPush(userId, tag, EJPushBalanceChangeType.consumption.getValue(), recordId, totalFee);
        }

    }

    /**
     * 更新审批公务订单
     *
     * @param oaCOrderApprovalOfficial 审批公务订单实体
     * @param totalFee                 总金额
     * @param date                     当前时间
     * @param userId                   用户id
     */
    @Override
    public void updateOaCOrderApprovalOfficial(OaCOrderApprovalOfficial oaCOrderApprovalOfficial, BigDecimal totalFee, Date date, Long userId, EPayType ePayType) {
        // 更新订单
        oaCOrderApprovalOfficial.setUpdateTime(date);
        oaCOrderApprovalOfficial.setUpdateUser(userId);
        oaCOrderApprovalOfficial.setPaymentType(ePayType.getType());
        oaCOrderApprovalOfficial.setActualFee(totalFee);
        oaCOrderApprovalOfficial.setOrderStatus(EOrderStatus.paymented.getType());
        int i = oaCOrderApprovalOfficialMapper.updateById(oaCOrderApprovalOfficial);
        if (i != 1) {
            throw PangException.create(EErrorCode.payFailure);
        }
        this.removeRedisOrderNo(oaCOrderApprovalOfficial.getOrderNo());
        // 删除邀约拼车redis中拼车
        this.deleteRedisOrder(oaCOrderApprovalOfficial.getCarpoolSerialNo());
    }

    /**
     * 更新部门额度订单
     *
     * @param oaCOrderDeptOfficial 个人公务订单实体
     * @param totalFee             总金额
     * @param date                 当前时间
     * @param userId               用户id
     */
    public void updateOaCOrderDectOfficial(OaCOrderDeptOfficial oaCOrderDeptOfficial, BigDecimal totalFee, Date date, Long userId, EPayType ePayType) {
        // 更新订单
        oaCOrderDeptOfficial.setOrderStatus(EOrderStatus.paymented.getType());
        oaCOrderDeptOfficial.setPaymentType(ePayType.getType());
        oaCOrderDeptOfficial.setActualFee(totalFee);
        oaCOrderDeptOfficial.setUpdateTime(date);
        oaCOrderDeptOfficial.setUpdateUser(userId+"");
        int i = oaCOrderDeptOfficialMapper.updateById(oaCOrderDeptOfficial);
        if (i != 1) {
            throw PangException.create(EErrorCode.payFailure);
        }
        this.removeRedisOrderNo(oaCOrderDeptOfficial.getOrderNo());
    }

    /**
     * 更新个人公务订单
     *
     * @param oaCOrderPersonalOfficial 个人公务订单实体
     * @param totalFee                 总金额
     * @param date                     当前时间
     * @param userId                   用户id
     */
    @Override
    public void updateOaCOrderPersonalOfficial(OaCOrderPersonalOfficial oaCOrderPersonalOfficial, BigDecimal totalFee, Date date, Long userId, EPayType ePayType) {
        // 更新订单
        oaCOrderPersonalOfficial.setOrderStatus(EOrderStatus.paymented.getType());
        oaCOrderPersonalOfficial.setUpdateTime(date);
        oaCOrderPersonalOfficial.setUpdateUser(userId+"");
        oaCOrderPersonalOfficial.setPaymentType(ePayType.getType());
        oaCOrderPersonalOfficial.setActualFee(totalFee);
        int i = oaCOrderPersonalOfficialMapper.updateById(oaCOrderPersonalOfficial);
        if (i != 1) {
            throw PangException.create(EErrorCode.payFailure);
        }
        this.removeRedisOrderNo(oaCOrderPersonalOfficial.getOrderNo());
        // 删除邀约拼车redis中拼车
        this.deleteRedisOrder(oaCOrderPersonalOfficial.getCarpoolSerialNo());
    }

    /**
     * 更新自费叫车订单
     *
     * @param oaCOrderPersonal 自费叫车订单实体
     * @param totalFee         总金额
     * @param date             当前时间
     * @param userId           用户id
     */
    @Override
    public void updateOaCOrderPersonal(OaCOrderPersonal oaCOrderPersonal, BigDecimal totalFee, Date date, Long userId, EPayType ePayType) {
        // 更新订单
        oaCOrderPersonal.setUpdateTime(date);
        oaCOrderPersonal.setUpdateUser(userId+"");
        oaCOrderPersonal.setOrderStatus(EOrderStatus.paymented.getType());
        oaCOrderPersonal.setActualFee(totalFee);
        oaCOrderPersonal.setPaymentType(ePayType.getType());
        int oaCOrderPersonalI = oaCOrderPersonalMapper.updateById(oaCOrderPersonal);
        if (oaCOrderPersonalI != 1) {
            throw PangException.create(EErrorCode.payFailure);
        }
        this.removeRedisOrderNo(oaCOrderPersonal.getOrderNo());
        // 删除邀约拼车redis中拼车
        this.deleteRedisOrder(oaCOrderPersonal.getCarpoolSerialNo());
    }

    /**
     * 初始化支付出参
     *
     * @return
     */
    private Map<String, Object> initUserPay() {
        Map<String, Object> result = new HashMap<>(16);
        result.put("payType", 2);
        result.put("payResultMap", new HashMap<>(16));
        result.put("payResultStr", "未知");
        return result;
    }

    /**
     * 验证订单
     *
     * @param orderStatus 订单状态
     * @return
     */
    @Override
    public void isOrder(Integer orderStatus) {
        if (!(EOrderStatus.normalOrderPendingPayment.getType().equals(orderStatus) ||
                EOrderStatus.cancelOrdersFeesPaid.getType().equals(orderStatus) ||
                EOrderStatus.cancelPendingPayment.getType().equals(orderStatus))) {
            throw PangException.create(EErrorCode.unUnpaidOrder);
        }
    }

    /**
     * 验证剩余额度是否是负数
     *
     * @param lastAmount 剩余额度
     * @return
     */
    private boolean isAmount(BigDecimal lastAmount) {
        if (lastAmount.compareTo(new BigDecimal(0)) == -1) {
            return false;
        }
        return true;
    }

    /**
     * 删除redis中订单
     *
     * @param orderNo
     */
    private void removeRedisOrderNo(String orderNo) {
        String key = RedisPrefixConstant.ORDER_OA_D_ORDER + orderNo;
        if (redisCommon.hashKey(key)) {
            redisCommon.remove(key);
        }
    }

    /**
     * 更细司机钱包
     *
     * @param driverId           司机id
     * @param userId             用户id
     * @param tag                租户
     * @param money              金额
     * @param orderNo            订单号
     * @param transactionOrderNo 交易凭证号
     */
    @Override
    public void updateDriverWallet(
            Long driverId,
            Long userId,
            String tag,
            BigDecimal money,
            String orderNo,
            EDRecordType edRecordType,
            String transactionOrderNo) {
        Date date = new Date();
        OaDWallet oaDWallet = oaDWalletMapper.selectOne(
                Wrappers.<OaDWallet>lambdaQuery()
                        .eq(OaDWallet::getTag, tag)
                        .eq(OaDWallet::getDriverId, driverId)
        );
        if (CheckUtil.objIsEmpty(oaDWallet)) {
            throw PangException.create(EErrorCode.unDriverWallet);
        }
        oaDWallet.setUpdateUser(userId);
        oaDWallet.setUpdateTime(date);
        oaDWallet.setWalletBalance(oaDWallet.getWalletBalance().add(money));
        int i = oaDWalletMapper.updateById(oaDWallet);
        if (i != 1) {
            throw PangException.create(EErrorCode.updateDriverWalletFailure);
        }
        OaDWalletRecord oaDWalletRecord = new OaDWalletRecord();
        oaDWalletRecord.setRecordId(IDUtil.nextId());
        oaDWalletRecord.setDriverId(driverId);
        oaDWalletRecord.setOrderNo(orderNo);
        oaDWalletRecord.setAmount(money);
        oaDWalletRecord.setRecordType(edRecordType.getValue());
        oaDWalletRecord.setIsTransaction(EIsTransaction.paySuccess.getValue());
        oaDWalletRecord.setTransactionTime(date);
        oaDWalletRecord.setTransactionOrderNo(transactionOrderNo);
        oaDWalletRecord.setTag(tag);
        oaDWalletRecord.setCreateUser(userId);
        oaDWalletRecord.setCreateTime(date);
        oaDWalletRecord.setUpdateUser(userId);
        oaDWalletRecord.setUpdateTime(date);
        oaDWalletRecord.setAmountRemark(edRecordType.getDesc());
        i = oaDWalletRecordMapper.insert(oaDWalletRecord);
        if (i != 1) {
            throw PangException.create(EErrorCode.insertDriverWalletRecordFailure);
        }
        // 更新司机日统计总收入
        // 司机日统计redis key
        String workStatisticsRedisKey = String.format("%s%s", RedisPrefixConstant.WORK_OA_D_WORK_STATISTICS, driverId);
        String workStatisticsJsonStr = redisCommon.getStr(workStatisticsRedisKey);
        // redis 有日统计数据
        if (CheckUtil.objIsNotEmpty(workStatisticsJsonStr)){
            OaDWorkStatistics oaDWorkStatistics = JSONObject.parseObject(workStatisticsJsonStr, OaDWorkStatistics.class);
            String dayTotalCost = oaDWorkStatistics.getDayTotalCost();
            if (CheckUtil.objIsEmpty(dayTotalCost)){
                dayTotalCost = "0";
            }
            BigDecimal dayTotalCostB = new BigDecimal(dayTotalCost);
            oaDWorkStatistics.setDayTotalCost(dayTotalCostB.add(money).toString());
            oaDWorkStatistics.setUpdateTime(date);
            oaDWorkStatistics.setUpdateUser(userId);
            redisCommon.set(workStatisticsRedisKey, JSON.toJSONString(oaDWorkStatistics));
        }
        // redis 中没有直接更新库
        else {
            List<OaDWorkStatistics> oaDWorkStatisticsList = oaDWorkStatisticsMapper.selectList(Wrappers.<OaDWorkStatistics>lambdaQuery().eq(OaDWorkStatistics::getTag, tag).eq(OaDWorkStatistics::getDriverId, driverId).orderByDesc(OaDWorkStatistics::getCreateTime));
            if (CheckUtil.objIsNotEmpty(oaDWorkStatisticsList)){
                OaDWorkStatistics oaDWorkStatistics = oaDWorkStatisticsList.get(0);
                String dayTotalCost = oaDWorkStatistics.getDayTotalCost();
                if (CheckUtil.objIsEmpty(dayTotalCost)){
                    dayTotalCost = "0";
                }
                BigDecimal dayTotalCostB = new BigDecimal(dayTotalCost);
                oaDWorkStatistics.setDayTotalCost(dayTotalCostB.add(money).toString());
                oaDWorkStatistics.setUpdateUser(userId);
                oaDWorkStatistics.setUpdateTime(date);
                oaDWorkStatisticsMapper.updateById(oaDWorkStatistics);
            }
        }
        // 更新司机订单
        List<OaDOrder> oaDOrders = oaDOrderMapper.selectList(Wrappers.<OaDOrder>lambdaQuery().eq(OaDOrder::getTag, tag).eq(OaDOrder::getOrderNo, orderNo));
        if (oaDOrders.size() == 1){
            OaDOrder oaDOrder = oaDOrders.get(0);
            oaDOrder.setOrderStatus(EOrderStatus.paymented.getType());
            oaDOrder.setUpdateUser(userId);
            oaDOrder.setUpdateTime(date);
            oaDOrderMapper.updateById(oaDOrder);
        }
        OaDUser oaDUser = oaDUserMapper.selectById(driverId);
        if (CheckUtil.objIsNotEmpty(oaDUser)){
            // 极光推送
            List<String> phones = new ArrayList<>();
            phones.add(oaDUser.getDriverPhone());
            this.driverPush(phones, orderNo, String.format(EDriverPushContent.driverPushContent.getDesc(), money));
        }
    }

    /**
     * 查询私用费
     * @param orderNo
     */
    @Override
    public BigDecimal getSelfFee(String orderNo, String tag){
        // 私用
        List<OaCSelfStroke> oaCSelfStrokes = oaCSelfStrokeMapper.selectList(Wrappers.<OaCSelfStroke>lambdaQuery().eq(OaCSelfStroke::getOrderNo, orderNo).eq(OaCSelfStroke::getTag, tag));
        BigDecimal priFee = new BigDecimal("0");
        for (OaCSelfStroke oaCSelfStroke : oaCSelfStrokes) {
            BigDecimal strokeTotalFee = oaCSelfStroke.getStrokeTotalFee();
            if (CheckUtil.objIsEmpty(strokeTotalFee)){
                continue;
            }
            priFee = priFee.add(strokeTotalFee);
        }
        return priFee;
    }

    @Override
    public Rv getPayInfo(UserPayParam userPayParam) {

        if (userPayParam.getType()==null||StringUtils.isBlank(userPayParam.getOrderId())||
                StringUtils.isBlank(userPayParam.getSubject())||userPayParam.getPrice()==null){
            return Rv.error(EErrorCode.missingArg);
        }

        Map<String, Object> result = this.initUserPay();
        // 用户钱包
        OaCWallet oaCWallet = oaCWalletMapper.selectOne(
                Wrappers.<OaCWallet>lambdaQuery()
                        .eq(OaCWallet::getUserId, userPayParam.getUserId())
                        .eq(OaCWallet::getTag, userPayParam.getTag())
        );
        if (CheckUtil.objIsEmpty(oaCWallet)) {
            throw PangException.create(EErrorCode.unWallet);
        }

        OaCOrderPersonal oaCOrderPersonal = oaCOrderPersonalMapper.selectOne(
                Wrappers.<OaCOrderPersonal>lambdaQuery()
                        .eq(OaCOrder::getUserId, userPayParam.getUserId())
                        .eq(OaCOrder::getTag, userPayParam.getTag())
                        .eq(OaCOrder::getOrderNo, userPayParam.getOrderId())
        );
        if (CheckUtil.objIsEmpty(oaCOrderPersonal)) {
            throw PangException.create(EErrorCode.unOrder);
        }

        payZFJC(oaCOrderPersonal, oaCWallet, new BigDecimal(userPayParam.getPrice()), new BigDecimal(userPayParam.getPrice()), userPayParam.getType(),
                userPayParam.getOrderId(), userPayParam.getUserId(), userPayParam.getTag(), result);
        Map<String,String> map=new HashMap<>();
        if(result.get("payResultStr")!=null){
            map.put("orderInfo",result.get("payResultStr").toString());
        }
        return Rv.wrap(map);
    }


    /**
     * 司机收到钱
     */
    private void driverPush(List<String> phones, String orderNo, String content){
        JSONObject jsonObject = new JSONObject();
        JSONObject result = new JSONObject();
        result.put("orderNo", orderNo);
        jsonObject.put("expand", JSON.toJSONString(result));
        PushInfoEntity pushInfoEntity = new PushInfoEntity();
        pushInfoEntity.setPushCode(EPushCode.driverMoneyPush.getValue());
        pushInfoEntity.setPhones(phones);
        pushInfoEntity.setExtras(jsonObject);
        pushInfoEntity.setContent(content);
        pushInfoEntity.setTag(TokenUtil.getTag());
        pushInfoEntity.setClientId(EJPushConfigKey.driver.getValue());
        BizResult bizResult = feignMessageSendService.pushMessage(pushInfoEntity);

        log.info("{}", bizResult.toString());

        if (bizResult.getCode() == 1) {
            log.info("推送成功");
        } else {
            log.info("推送失败");
        }
    }

    /**
     * 邀约拼车删除redis中的订单
     * @param carpoolSerialNo 邀约拼车流水号
     */
    private void deleteRedisOrder(String carpoolSerialNo){
        // 邀约拼车流水号
//        if (CheckUtil.strIsNotEmpty(carpoolSerialNo)){
//            List<OaCOrder> oaCOrders = orderCommon.getOrderByCarpoolSerialNo(carpoolSerialNo);
//            // 完成订单个数
//            Integer completeOrder = 0;
//            for (OaCOrder oaCOrder : oaCOrders) {
//                Integer orderStatus = oaCOrder.getOrderStatus();
//                if (EOrderStatus.cancelOrderNoNeedPayment.getType().equals(orderStatus) ||
//                        EOrderStatus.abnormalEndOrder.getType().equals(orderStatus) ||
//                        EOrderStatus.paymented.getType().equals(orderStatus)){
//                    completeOrder += 1;
//                }
//            }
//            if (completeOrder > 0){
//                redisCommon.remove(RedisPrefixConstant.PICK_UP_RULES + carpoolSerialNo);
//            }
//        }
    }
}
